package com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.TreeMap;

public class RSASignDemo {
    // 机构号和商户号配置
    private static final String AGENT_ID = "your_agent_id";
    private static final String CUST_ID = "your_cust_id";
    private static final String PUBLIC_KEY_PEM = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxZ933I5F2uwSq3nLlhT7O8wNg8lSpAP4ATP/CHIcvt6QWWk6WLMoJVenJnKaF/nBnnXvb2Bp1GnlxW86a55uQLtbYgbuVZFm8qE3WhXVtEx9dqe3DOS/CqZXbrDEygclBaATZutKYvH3Z7Gl6uRfz63GKVhEJ0BbmrEP7ybQ3wTyXAD37WeiKgkYewKGuYEqnA6uV1/3H9dpiXauj5AcfVJ7ZV1QQHYm4fA4YJTiNB5oKGXiOvMO7lyfisqMrgjsQOwiTUHxxEmMk9HR+vCbVkA4GfynNBTjo7xG93lS0SBNIkf0R8D4PG9NsBVKwaEHyebja1Ak6q8kMBmc/L0azwIDAQAB";

    public static void main(String[] args) throws Exception {
        // 生成签名
        String signature = sign();
        System.out.println("签名结果: " + signature);

        // 验签（根据PHP逻辑实现）
        String decodedHash = decode("k3qi6zUkK2vgj56p2Rvin801AK3JJIgowOVfp2BWyf+XSCAGFImG4X5DiyeFlQ1u02CTdEXdxV2OuaIumJdE7MtkkqYasqir8vFGLVVP1hxNhV0rSuNuhYxjFpjKUAIsGoOc9BgA/EYE3LjWXyt7ubFdkDc9yBJf45TndaylbsdcpPd2Blaq/hm10LAFGqOJhEPPhSOx+XD2R2ZWt6Lh2zNeoSB8Scg5zNaqNeX1xzMFIGhBktfkaehWvZaPGXGKa4Dluw95UJ73ZDib7Pq0c0yZ0PORc1QogZylMkgNFIpqH8W/HVU0ocfm8+UJGDSuEldNlYaY/na1nGRWcdhxuQ==");
        System.out.println("解密哈希: " + decodedHash);
    }

    /**
     * 签名方法（对应PHP sign()）
     */
    public static String sign() throws Exception {
        // 1. 构造有序参数
        TreeMap<String, String> params = new TreeMap<>();
        params.put("agetId", AGENT_ID);
        params.put("custId", CUST_ID);
        params.put("timeStamp", "1620000000"); // 固定测试时间戳
        params.put("version", "1.0.0");

        // 2. 拼接字符串
        StringBuilder contentBuilder = new StringBuilder();
        params.forEach((k, v) -> contentBuilder.append("&").append(k).append("=").append(v));
        String content = contentBuilder.toString();

        // 3. 计算SHA256
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = md.digest(content.getBytes(StandardCharsets.UTF_8));
        String hexHash = bytesToHex(hashBytes);

        // 4. RSA加密
        PublicKey publicKey = getPublicKey(PUBLIC_KEY_PEM);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        byte[] inputBytes = hexHash.getBytes(StandardCharsets.UTF_8);
        int blockSize = 117;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        for (int i = 0; i < inputBytes.length; i += blockSize) {
            byte[] chunk = Arrays.copyOfRange(inputBytes, i, Math.min(i + blockSize, inputBytes.length));
            outputStream.write(cipher.doFinal(chunk));
        }

        return Base64.getEncoder().encodeToString(outputStream.toByteArray());
    }

    /**
     * 验签方法（对应PHP decode()）
     */
    public static String decode(String signature) throws Exception {
        byte[] encryptedBytes = GtzfPayBase64.decode2Byte(signature);
        PublicKey publicKey = GtzfPayRsaUtil.getPublicKey(PUBLIC_KEY_PEM);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int blockSize = 256;

        for (int i = 0; i < encryptedBytes.length; i += blockSize) {
            byte[] chunk = Arrays.copyOfRange(encryptedBytes, i, Math.min(i + blockSize, encryptedBytes.length));
            outputStream.write(cipher.doFinal(chunk));
        }

        return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
    }

    /**
     * 从PEM字符串加载公钥
     */
    private static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] keyBytes = GtzfPayBase64.decode2Byte(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(spec);
    }

    /**
     * 字节数组转十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = String.format("%02x", b);
            hexString.append(hex);
        }
        return hexString.toString();
    }
}